package cz.data.auth.security;

import cz.data.common.core.DataConstant;
import cz.data.common.core.DataUser;
import cz.data.common.redis.service.RedisService;
import cz.data.common.utils.ResponseUtil;
import cz.data.domain.system.model.vo.LoginUserInfoVo;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
import org.springframework.security.oauth2.jwt.*;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.UUID;

@Component
public class LoginAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    private final JwsHeader jwsHeader = JwsHeader.with(SignatureAlgorithm.RS256).build();

    private final JwtEncoder jwtEncoder;
    private final RedisService redisService;

    public LoginAuthenticationSuccessHandler(JwtEncoder jwtEncoder, RedisService redisService) {
        this.jwtEncoder = jwtEncoder;
        this.redisService = redisService;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        DataUser dataUser = (DataUser) authentication.getPrincipal();
        String jti = UUID.randomUUID().toString();
        Jwt jwt = jwtEncoder.encode(jwtEncoderParameters(jti, dataUser));
        LoginUserInfoVo loginUserInfoVo = LoginUserInfoVo.form(jwt.getTokenValue(), dataUser);
        ResponseUtil.makeResponse(
                response, MediaType.APPLICATION_JSON_VALUE,
                HttpServletResponse.SC_OK,
                loginUserInfoVo);
        redisService.set(DataConstant.Token.JWT_CACHE_PREFIX + jti, dataUser, 3600L);
    }

    private JwtEncoderParameters jwtEncoderParameters(String jti, DataUser dataUser) {
        return JwtEncoderParameters.from(jwsHeader, claimsBuilder(jti, dataUser));
    }

    private JwtClaimsSet claimsBuilder(String jti, DataUser dataUser) {
        return JwtClaimsSet.builder()
                .id(jti)
                .subject(dataUser.getUsername())
                .issuedAt(Instant.now())
                .expiresAt(Instant.now().plus(60, ChronoUnit.MINUTES))
                .build();
    }
}
